home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / macos / uae069b2.src.cpt.hqx / UAE069ß2.SRC.CPT / uae069fl2.src / disk.c < prev    next >
C/C++ Source or Header  |  1997-06-25  |  15KB  |  642 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Floppy disk emulation
  5.   *
  6.   * (c) 1995 Bernd Schmidt, Hannu Rummukainen
  7.   */
  8.  
  9. #include <stdio.h>
  10.  
  11. #include "sysconfig.h"
  12. #include "sysdeps.h"
  13.  
  14. #include "config.h"
  15. #include "options.h"
  16. #include "my_memory.h"
  17. #include "gensound.h"
  18. #include "sounddep/sound.h"
  19. #include "events.h"
  20. #include "custom.h"
  21. #include "ersatz.h"
  22. #include "disk.h"
  23. #include "gui.h"
  24. #include "zfile.h"
  25. #include "autoconf.h"
  26. #include "readcpu.h"
  27. #include "newcpu.h"
  28. #include "xwin.h"
  29. #include "osemu.h"
  30. #include "execlib.h"
  31.  
  32. #define FLOPPY_GAP_LEN 360
  33.  
  34. #define FLOPPY_SPEED 4
  35.  
  36. uae_u16* mfmwrite;
  37. static uae_u16 mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */
  38.  
  39. static int side, direction, step;
  40. static uae_u8 selected = 15;
  41. static int dskready;
  42.  
  43. typedef struct {
  44.     uae_u16 sync;
  45.     uae_u16 len;
  46.     uae_u32 offs;
  47. } trackid;
  48.  
  49. #define MAX_TRACKS 328
  50.  
  51. typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype;
  52. typedef struct {
  53.     FILE *diskfile;
  54.     drive_filetype filetype;
  55.     trackid trackdata[MAX_TRACKS];
  56.     unsigned int buffered_cyl, buffered_side;
  57.     unsigned int cyl;
  58.     int side;
  59.     int motoroff;
  60.     int wrprot;
  61.     uae_u16 bigmfmbuf[0x4000];
  62.     int tracklen;
  63.     unsigned long last_cycles;
  64.     int mfmpos;
  65.     unsigned int num_tracks, num_secs;
  66.     /* dskchange is set to a small number when a disk is removed. At a step
  67.      * impulse, it is reset if there is a new disk in the drive or counted
  68.      * down to 1 if the drive contains a disk. DISK_check_change will only
  69.      * insert a new disk when dskchange is 1, or if the dskchange_time timer
  70.      * expires. The last condition can happen if AmigaOS isn't running and a
  71.      * game/demo doesn't use the step motor to check for a new disk.
  72.      */
  73.     int dskchange;
  74.     int dskchange_time;
  75. } drive;
  76.  
  77. drive floppy[4];
  78.  
  79. static void drive_fill_bigbuf(drive *drv);
  80.  
  81. FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot)
  82. {
  83.     FILE *f = zfile_open(fname, "r+b");
  84.     if (f) {
  85.     if (wrprot)
  86.         *wrprot = 0;
  87.     } else {
  88.     if (wrprot)
  89.         *wrprot = 1;
  90.     f = zfile_open(fname, "rb");
  91.     }
  92.     if (!leave_open)
  93.     fclose (f);
  94.     return f;
  95. }
  96.  
  97. static int drive_insert(drive *drv, int dnum, const char *fname)
  98. {
  99.     unsigned char buffer[10];
  100.  
  101.     drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot);
  102.     if (drv->diskfile == 0)
  103.     return 0;
  104.  
  105.     strncpy (currprefs.df[dnum], fname, 255);
  106.     currprefs.df[dnum][255] = 0;
  107.     strncpy (changed_prefs.df[dnum], fname, 255);
  108.     changed_prefs.df[dnum][255] = 0;
  109.     gui_filename(dnum, fname);
  110.  
  111.     fread(buffer, sizeof(char), 8, drv->diskfile);
  112.     if (strncmp((char *)buffer,"UAE--ADF",8) == 0) {    
  113.     int offs = 160*4+8;
  114.     int i;
  115.     
  116.         drv->filetype = ADF_EXT1;
  117.     drv->num_tracks = 160;
  118.     drv->num_secs = 11;
  119.         
  120.     drv->wrprot = 1; /* write to adf_ext1 not implemented */
  121.     for(i=0; i<160; i++) {
  122.         fread(buffer, 4, 1, drv->diskfile);
  123.         drv->trackdata[i].sync = buffer[0]*256 + buffer[1];
  124.         drv->trackdata[i].len = buffer[2]*256 + buffer[3];
  125.         drv->trackdata[i].offs = offs;
  126.         offs += drv->trackdata[i].len;
  127.     }
  128.     } else {
  129.     unsigned int i;
  130.     
  131.         drv->filetype = ADF_NORMAL;
  132.  
  133.     fseek(drv->diskfile,0,SEEK_END);
  134.     i = ftell(drv->diskfile);
  135.     fseek(drv->diskfile,0,SEEK_SET);
  136.     
  137.     /* High-density disk? */
  138.     if (i >= 160*22*512)
  139.         drv->num_tracks = i / (512*(drv->num_secs = 22));
  140.     else
  141.         drv->num_tracks = i / (512*(drv->num_secs = 11));
  142.     
  143.     if (drv->num_tracks > MAX_TRACKS)
  144.         fprintf(stderr, "Your diskfile is too big!\n");
  145.     for(i = 0; i < drv->num_tracks; i++) {
  146.         drv->trackdata[i].len = 512 * drv->num_secs;
  147.         drv->trackdata[i].sync = 0;
  148.         drv->trackdata[i].offs = i * 512 * drv->num_secs;
  149.     }
  150.     }
  151.     drv->buffered_side = 2; /* will force read */
  152.     return 1;
  153. }
  154.  
  155. static int drive_empty(drive *drv)
  156. {
  157.     return drv->diskfile == 0; 
  158. }
  159.  
  160. static void drive_step(drive *drv)
  161. {
  162.     if (!drive_empty(drv))
  163.     drv->dskchange = 0;
  164.     else if (drv->dskchange > 1) {
  165. /*    printf("Stepping...\n");
  166.     drv->dskchange--;*/
  167.     }
  168.     if (direction) {
  169.     if (drv->cyl) drv->cyl--;
  170.     } else {
  171.     if (drv->cyl < drv->num_tracks/2) drv->cyl++;
  172.     }
  173. }
  174.  
  175.  
  176. static int drive_track0(drive *drv) 
  177. {
  178.     return drv->cyl == 0; 
  179. }
  180.  
  181. static int drive_writeprotected(drive *drv) 
  182. {
  183.     return drv->wrprot || drv->diskfile == NULL; 
  184. }
  185.  
  186. static int drive_running(drive *drv)
  187. {
  188.     return !drv->motoroff; 
  189. }
  190.  
  191. static void drive_motor(drive *drv, int off)
  192. {
  193.     if (drv->motoroff && !off) {
  194.     drv->last_cycles = cycles;
  195.     drv->mfmpos = 0;
  196.     eventtab[ev_diskindex].active = 1;
  197.     if (drv->tracklen)
  198.         eventtab[ev_diskindex].evtime = FLOPPY_SPEED * drv->tracklen + cycles;
  199.     else
  200.         eventtab[ev_diskindex].evtime = cycles + 1000;
  201.     eventtab[ev_diskindex].oldcycles = cycles;
  202.     } else if (off)
  203.     eventtab[ev_diskindex].active = 0;
  204.     drv->motoroff = off;
  205.     events_schedule();
  206. }
  207.  
  208. static void drive_fill_bigbuf(drive *drv)
  209. {
  210.     int tr = drv->cyl*2 + side;
  211.  
  212.     if (!drv->diskfile) {
  213.     drv->tracklen = 10;
  214.     memset (drv->bigmfmbuf,0xaa,drv->tracklen*2);
  215.     return;
  216.     }
  217.     if (drv->buffered_cyl == drv->cyl && drv->buffered_side == side)
  218.     return;
  219.  
  220.     if (drv->trackdata[tr].sync == 0) {
  221.     /* Normal AmigaDOS format track */
  222.     unsigned int sec;
  223.     drv->tracklen = drv->num_secs*544 + FLOPPY_GAP_LEN;
  224.     memset(drv->bigmfmbuf,0xaa,FLOPPY_GAP_LEN*2);
  225.  
  226.     for (sec = 0; sec < drv->num_secs; sec++) {
  227.         uae_u8 secbuf[544];
  228.         int i;
  229.         uae_u16 *mfmbuf = drv->bigmfmbuf + 544*sec + FLOPPY_GAP_LEN;
  230.         uae_u32 deven,dodd;
  231.         uae_u32 hck=0,dck=0;
  232.         
  233.         secbuf[0] = secbuf[1] = 0x00;
  234.         secbuf[2] = secbuf[3] = 0xa1;
  235.         secbuf[4] = 0xff;
  236.         secbuf[5] = tr;
  237.         secbuf[6] = sec;
  238.         secbuf[7] = drv->num_secs-sec;
  239.  
  240.         for(i = 8; i < 24; i++)
  241.         secbuf[i] = 0;
  242.     
  243.         fseek(drv->diskfile,
  244.           drv->trackdata[tr].offs + sec*512, 
  245.           SEEK_SET);
  246.         fread(&secbuf[32],1,512,drv->diskfile);
  247.  
  248.         mfmbuf[0] = mfmbuf[1] = 0xaaaa;
  249.         mfmbuf[2] = mfmbuf[3] = 0x4489;
  250.  
  251.         deven = ((secbuf[4] << 24) | (secbuf[5] << 16) 
  252.              | (secbuf[6] << 8) | (secbuf[7]));
  253.         dodd = deven >> 1;
  254.         deven &= 0x55555555; dodd &= 0x55555555;
  255.  
  256.         mfmbuf[4] = dodd >> 16;
  257.         mfmbuf[5] = dodd;
  258.         mfmbuf[6] = deven>> 16;
  259.         mfmbuf[7] = deven;
  260.  
  261.         for (i = 8; i < 48; i++)
  262.         mfmbuf[i] = 0;
  263.         for (i = 0; i < 512; i += 4){
  264.         deven = ((secbuf[i+32] << 24) | (secbuf[i+33] << 16)
  265.              | (secbuf[i+34] << 8) | (secbuf[i+35]));
  266.         dodd = deven >> 1;
  267.         deven &= 0x55555555; dodd &= 0x55555555;
  268.         mfmbuf[(i>>1)+32] = dodd >> 16;
  269.         mfmbuf[(i>>1)+33] = dodd;
  270.         mfmbuf[(i>>1)+256+32] = deven >> 16;
  271.         mfmbuf[(i>>1)+256+33] = deven;
  272.         }
  273.  
  274.         for(i = 4; i < 24; i += 2)
  275.         hck ^= (mfmbuf[i] << 16) | mfmbuf[i+1];
  276.     
  277.         deven = dodd = hck; dodd >>= 1;
  278.         mfmbuf[24] = dodd >> 16; mfmbuf[25] = dodd;
  279.         mfmbuf[26] = deven>> 16; mfmbuf[27] = deven;
  280.     
  281.         for(i = 32; i < 544; i += 2)
  282.         dck ^= (mfmbuf[i] << 16) | mfmbuf[i+1];
  283.     
  284.         deven = dodd = dck; dodd >>= 1;
  285.         mfmbuf[28] = dodd >> 16; mfmbuf[29] = dodd;
  286.         mfmbuf[30] = deven>> 16; mfmbuf[31] = deven;
  287.     }
  288.     } else {
  289.     int i;
  290.     drv->tracklen = drv->trackdata[tr].len/2 + 1;
  291.     drv->bigmfmbuf[0] = drv->trackdata[tr].sync;
  292.     fseek(drv->diskfile, drv->trackdata[tr].offs, SEEK_SET);
  293.     fread(drv->bigmfmbuf+1, 1, drv->trackdata[tr].len, drv->diskfile);
  294.     for (i = 0; i < drv->trackdata[tr].len/2; i++) {
  295.         uae_u16 *mfm = drv->bigmfmbuf + i + 1;
  296.         uae_u8 *data = (uae_u8 *)mfm;
  297.         
  298.         *mfm = 256 * *data + *(data+1);
  299.     }
  300.     }
  301.     drv->buffered_side = side;
  302.     drv->buffered_cyl = drv->cyl;
  303.     drv->last_cycles = cycles;
  304.     drv->mfmpos = 0;
  305. }
  306.  
  307. static int drive_get_data(drive *drv, uae_u16 *mfm, uae_u16 *byt)
  308. {
  309.     int offset,mfmpos;
  310.  
  311.     drive_fill_bigbuf(drv);
  312.     offset = (cycles - drv->last_cycles) / FLOPPY_SPEED;
  313.     mfmpos = (drv->mfmpos + offset) % drv->tracklen;
  314.     drv->last_cycles += offset*FLOPPY_SPEED;
  315.     drv->mfmpos = mfmpos;
  316.     *mfm = drv->bigmfmbuf[mfmpos];
  317.     return offset > 0;
  318. }
  319.  
  320. #define MFMMASK 0x55555555
  321. static __inline__ uae_u32 getmfmlong(uae_u16* mbuf) 
  322. {
  323.     return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
  324. }
  325.  
  326. static void drive_write_data(drive *drv, uae_u16 *mbuf, int length)
  327. {
  328.     int i, secwritten = 0;
  329.     uae_u32 odd, even, chksum, id, dlong;
  330.     uae_u8* secdata;
  331.     uae_u8 secbuf[544];
  332.     uae_u16 *mend = mbuf + length;
  333.  
  334.     if (drive_writeprotected(drv))
  335.     return;
  336.  
  337.     drive_fill_bigbuf(drv);
  338.     mend -= (4 + 16 + 8 + 512);
  339.     while (length > 0) {
  340.     int trackoffs;
  341.  
  342.     do {
  343.         while (*mbuf++ != 0x4489) {
  344.         if (mbuf >= mend) return;
  345.         }
  346.     } while (*mbuf++ != 0x4489);
  347.     
  348.     odd = getmfmlong(mbuf);
  349.     even = getmfmlong(mbuf+2);
  350.     mbuf += 4;    
  351.     id = (odd << 1) | even;
  352.  
  353.     trackoffs = (id & 0xff00) >> 8;
  354.     if (trackoffs > 10) {
  355.         printf("Disk write: weird sector number %d\n", trackoffs);
  356.         continue;
  357.     }
  358.     chksum = odd ^ even;
  359.     for (i=0; i<4; i++) {
  360.         odd = getmfmlong(mbuf);
  361.         even = getmfmlong(mbuf+8);
  362.         mbuf += 2;
  363.         
  364.         dlong = (odd << 1) | even;
  365.         if (dlong)  secwritten = -200;
  366.         chksum ^= odd ^ even;
  367.     }  /* could check here if the label is nonstandard */
  368.     mbuf += 8;
  369.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  370.     if ((((odd << 1) | even) != chksum) || 
  371.         (((id & 0x00ff0000) >> 16) != drv->cyl*2 + side)) {
  372.         printf("Disk write: checksum error on sector header\n");
  373.         continue;
  374.     }
  375.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  376.     chksum = (odd << 1) | even;
  377.     secdata = secbuf + 32;
  378.     for (i=0; i<128; i++) {
  379.         odd = getmfmlong(mbuf); even = getmfmlong(mbuf+256); mbuf += 2;
  380.         dlong = (odd << 1) | even;
  381.         *secdata++ = dlong >> 24; *secdata++ = (dlong >> 16) & 0xff;
  382.         *secdata++ = dlong >> 8; *secdata++ = dlong;
  383.         chksum ^= odd ^ even;
  384.     }
  385.     mbuf += 256;
  386.     if (chksum) {
  387.         printf("Disk write: data checksum error\n");
  388.         continue;
  389.     }
  390.     secwritten++;
  391.     fseek(drv->diskfile, 
  392.           drv->trackdata[drv->cyl*2 + side].offs + trackoffs*512,
  393.           SEEK_SET);
  394.     fwrite(secbuf+32, sizeof(uae_u8), 512, drv->diskfile);
  395.     }
  396.     drv->buffered_side = 2; /* will force read */
  397.     
  398.     if (secwritten == 0) 
  399.     printf("Disk write in unsupported format\n");
  400.     if (secwritten < 0)
  401.     printf("Disk write: sector labels ignored\n");
  402. }
  403.  
  404.  
  405. static void drive_eject(drive *drv)
  406. {
  407.     if (!drive_empty(drv))
  408.     zfile_close(drv->diskfile);
  409.     
  410.     drv->dskchange = 4;
  411.     drv->dskchange_time = 20;
  412. /*    printf("setting changed bit %d\n", drv-floppy);*/
  413.     drv->diskfile = 0;
  414. }
  415.  
  416. /* We use this function if we have no Kickstart ROM. 
  417.  * No error checking - we trust our luck. */
  418. void DISK_ersatz_read (int tr, int sec, uaecptr dest)
  419. {
  420.     int i;
  421.     uae_u8 *dptr = get_real_address(dest);
  422.     fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec*512, SEEK_SET);
  423.     fread (dptr, 1, 512, floppy[0].diskfile);
  424. }
  425.  
  426. void disk_eject(int num)
  427. {
  428.     gui_filename(num, "");
  429.     drive_eject(floppy + num);
  430.     *currprefs.df[num] = *changed_prefs.df[num] = 0;
  431. }
  432.  
  433. void disk_insert(int num, const char *name)
  434. {
  435.     /* just to be sure */
  436.     drive_eject(floppy + num);
  437.     drive_insert(floppy + num, num, name);
  438. }
  439.  
  440. void DISK_check_change (void)
  441. {
  442.     int i;
  443.     static int count = 0;
  444.     count++;
  445.  
  446.     for (i = 0; i < 4; i++) {    
  447.     if (strcmp (currprefs.df[i], changed_prefs.df[i]) != 0) {
  448.         if (currprefs.df[i][0] != '\0') {
  449.         drive_eject(floppy + i);
  450.         currprefs.df[i][0] = '\0';
  451.         /*printf("Ejecting %d at %d\n", i, count);*/
  452.         } else if (floppy[i].dskchange == 1) {
  453.         /* In theory, it should work without the dskchange test.
  454.          * In practice, it doesn't. */
  455.         drive_insert (floppy + i, i, changed_prefs.df[i]);
  456.         /*printf("Inserting %d at %d\n", i, count);*/
  457.         } else if (floppy[i].dskchange > 1 && floppy[i].dskchange_time > 0) {
  458.         /* Force the dskchange bit to go to 1 after a given timeout */
  459.         /*printf("Countdown %d at %d\n", i, count);*/
  460.         if (--floppy[i].dskchange_time == 0) {
  461.             /*printf("Timeout %d at %d\n", i, count);*/
  462.             floppy[i].dskchange = 1;
  463.         }
  464.         }
  465.     }
  466.     }
  467. }
  468.  
  469. int disk_empty(int num)
  470. {
  471.     return drive_empty(floppy + num);
  472. }
  473.  
  474. void DISK_init()
  475. {
  476.     int i;
  477.     for (i = 0; i < 4; i++)
  478.     if (!drive_insert (floppy+i, i, currprefs.df[i]))
  479.         disk_eject (i);
  480.  
  481.     if (disk_empty (0))
  482.     fprintf(stderr, "No disk in drive 0.\n");
  483. }
  484.  
  485. static int ledstate[] = { 0,0,0,0 };
  486.  
  487. void DISK_select(uae_u8 data)
  488. {
  489.     int step_pulse;
  490.     int dr;
  491.     
  492.     if (selected != ((data >> 3) & 15)) 
  493.     dskready = 0;
  494.     selected = (data >> 3) & 15;
  495.     side = 1 - ((data >> 2) & 1);
  496.  
  497.     direction = (data >> 1) & 1;
  498.     step_pulse = data & 1;
  499.     if (step != step_pulse) {
  500.     step = step_pulse;
  501.     if (step == 0){
  502.         for (dr = 0; dr < 4; dr++){
  503.         if (!(selected & (1 << dr))) {
  504.             drive_step(floppy + dr);
  505.         }
  506.         }
  507.     }
  508.     }
  509.     for (dr = 0; dr < 4; dr++){
  510.     if (!(selected & (1<<dr))) {
  511.         drive_motor(floppy + dr, data >> 7);
  512.     }
  513.     }
  514.     for (dr = 0; dr < 4; dr++) {
  515.     int state = (!(selected & (1<<dr))) | !floppy[dr].motoroff;
  516.     if (state != ledstate[dr])
  517.         gui_led (dr+1, state);
  518.     ledstate[dr] = state;
  519.     }
  520. }
  521.  
  522. uae_u8 DISK_status()
  523. {
  524.     uae_u8 st = 0x3c;
  525.     int dr;
  526.     
  527.     for (dr = 0; dr < 4; dr++){
  528.     drive *drv = floppy + dr;
  529.     if (!(selected & (1 << dr))) {
  530.         if (drive_running(drv)){
  531.         if (dskready) st &= ~0x20;
  532.         dskready = 1;
  533.         } else {
  534.         st &= ~0x20; /* report drive ID */
  535.         }
  536.  
  537.         if (drive_track0 (drv)) { st &= ~0x10; }
  538.         if (drive_writeprotected (drv)) { st &= ~8; }
  539.         if (drv->dskchange) {
  540.         /*printf("changed bit set: %d\n",dr); */
  541.         st &= ~0x4;
  542.         if (drv->dskchange > 1)
  543.             drv->dskchange--;
  544.         }
  545.     }
  546.     }
  547.     return st;
  548. }
  549.  
  550. int DISK_GetData(uae_u16 *mfm,uae_u16 *byt)
  551. {
  552.     int dr;
  553.     for (dr = 0; dr < 4; dr++){
  554.     if (!(selected & (1<<dr))) {
  555.         return drive_get_data (floppy + dr, mfm, byt);
  556.     }
  557.     }
  558.     return 0;
  559. }
  560.  
  561. static uae_u16 mfm_read_buffer[0x4000];
  562. static int mfm_read_length;
  563.  
  564. int DISK_PrepareReadMFM(int length, uae_u16 sync, int use_sync)
  565. {
  566.     int dr;
  567.     
  568.     mfm_read_length = 0;
  569.     
  570.     for (dr = 0; dr < 4; dr++) {
  571.     if (!(selected & (1<<dr))) {
  572.         int time = 0;
  573.         uae_u16 *mfmp = mfm_read_buffer;
  574.         drive *drv = floppy + dr;
  575.         int offset,mfmpos;
  576.  
  577.         drive_fill_bigbuf(drv);
  578.  
  579.         offset = (cycles - drv->last_cycles) / FLOPPY_SPEED;
  580.         mfmpos = (drv->mfmpos + offset) % drv->tracklen;
  581.         drv->last_cycles += offset*FLOPPY_SPEED;
  582.         drv->mfmpos = mfmpos;
  583.         mfmpos++; mfmpos %= drv->tracklen;
  584.         while (drv->bigmfmbuf[mfmpos] != sync && mfmpos != drv->mfmpos && use_sync)
  585.         mfmpos = (mfmpos + 1) % drv->tracklen, time++;
  586.  
  587.         if (drv->bigmfmbuf[mfmpos] != sync && use_sync) {
  588.         write_log ("warning: sync not found on disk read\n");
  589.         return 0;
  590.         } else
  591.         mfmpos++;
  592.  
  593.         mfm_read_length = length;
  594.  
  595.         while (length--) {
  596.         *mfmp++ = drv->bigmfmbuf[mfmpos];
  597.         mfmpos = (mfmpos + 1) % drv->tracklen;
  598.         time++;
  599.         }
  600.  
  601.         return time*FLOPPY_SPEED;
  602.     }
  603.     }
  604.     return 0;    
  605. }
  606.  
  607. int DISK_ReadMFM(uaecptr target)
  608. {
  609.     int i;
  610.     uae_u8 *mfmp = get_real_address(target);
  611.     
  612.     if (!chipmem_bank.check(target, mfm_read_length * 2)) {
  613.     fprintf(stderr, "warning: Bad disk DMA read pointer\n");
  614.     return 0;
  615.     }
  616.  
  617.     for (i = 0; i < mfm_read_length; i++) {
  618.     *mfmp++ = mfm_read_buffer[i] >> 8;
  619.     *mfmp++ = mfm_read_buffer[i];
  620.     }
  621.     return 1;
  622. }
  623.  
  624. void DISK_InitWrite()
  625. {
  626.     mfmwrite = mfmwrbuffer;
  627. }
  628.  
  629. void DISK_WriteData(int length)
  630. {
  631.     int dr;
  632.     for (dr=0;dr<4;dr++){
  633.     if (!(selected & (1<<dr))) {
  634.         drive_write_data(floppy + dr, mfmwrbuffer, length);
  635.     }
  636.     }
  637. }
  638.  
  639. void trackdisk_install(void)
  640. {
  641. }
  642.